package edu.iscas.xcheck.analysis.dom.checker;

import java.util.Arrays;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfFloat;
import org.opencv.core.MatOfInt;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

import edu.iscas.xcheck.analysis.dom.layout.AGNode;

public class IMGHandler {
	private final static double THREADSHOLD_BHATTACHARYYA = 0.2;
	private final static double THREADSHOLD_CORREL = 0.8;
	private final static double THREADSHOLD_CHISQR = 1;
	private Mat source1,target1;
	private Mat source2,target2;
	private String path1, path2;
	private String browser1, browser2;
	static{
//		System.out.println(PropertiesUtil.class.getClassLoader().getResource("opencv_java2410.dll").getPath());
//		System.load(PropertiesUtil.class.getClassLoader().getResource("opencv_java2410.dll").getPath());
//		System.load("./opencv_java2410.dll");
//		System.setProperty("java.library.path", "E:/opencv/build/java/x64");
//		System.out.println(System.getProperty("java.library.path"));
		try{
			System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
		}catch(Exception e){
			e.printStackTrace();
		}
//		System.out.println(System.getProperty("java.library.path"));
	}
	
	public IMGHandler(String path1, String path2, String browser1, String browser2){
		source1 = Highgui.imread(path1);
		source2 = Highgui.imread(path2);
		target1 = source1.clone();
		target2 = source2.clone();
		this.path1 = path1;
		this.path2 = path2;
		this.browser1 = browser1;
		this.browser2 = browser2;
	}
	/**
	 * write diff image
	 */
	public void finish(){
//		paintRect(target1, 0, 558, 653, 844, 947);
//		paintRect(target2, 0, 573+91, 650+91, 850+196, 938+196);
		Highgui.imwrite(path1.replace(".png", "_"+browser2+"_diff.png"), target1);
		Highgui.imwrite(path2.replace(".png", "_"+browser1+"_diff.png"), target2);
		source1.release();
		source2.release();
		target1.release();
		target2.release();
	}
	public void setRectInImage(int index, AGNode node1, AGNode node2){
		if(node1 != null){
			paintRect(target1, index, node1.y1, node1.y2, node1.x1, node1.x2);
		}else{
			paintRect(target1, index, 0, 0, 0, 0);
		}
		if(node2 != null){
//			paintRect(target2, index, node2.y1+91, node2.y2+91, node2.x1+196, node2.x2+196);
			paintRect(target2, index, node2.y1, node2.y2, node2.x1, node2.x2);
		}else{
			paintRect(target2, index, 0, 0, 0, 0);
		}
	}
	public void setRectInImage(AGNode node1, AGNode node2){
		if(node1 != null){
			paintRect(target1, 0, node1.y1, node1.y2, node1.x1, node1.x2);
		}else{
			paintRect(target1, 0, 0, 0, 0, 0);
		}
		if(node2 != null){
//			paintRect(target2, index, node2.y1+91, node2.y2+91, node2.x1+196, node2.x2+196);
			paintRect(target2, 0, node2.y1, node2.y2, node2.x1, node2.x2);
		}else{
			paintRect(target2, 0, 0, 0, 0, 0);
		}
	}
	private void paintRect(Mat target, int index, int rowStart, int rowEnd, int colStart, int colEnd){
		if(index == 5){
			System.out.println();
		}
		rowStart = rowStart>0?rowStart:0;
		colStart = colStart>0?colStart:0;
		rowStart = rowStart<target.rows()?rowStart:target.rows();
		colStart = colStart<target.cols()?colStart:target.cols();
		rowEnd = rowEnd>0?rowEnd:0;
		colEnd = colEnd>0?colEnd:0;
		rowEnd = rowEnd<target.rows()?rowEnd:target.rows();
		colEnd = colEnd<target.cols()?colEnd:target.cols();
		//paint row
		for(int row=rowStart;row<=rowEnd;row++){
			target.put(row, colStart, 0,0,255);
//			target.put(row, colStart+1, 0x00,0x00,0xff);
//			target.put(row, colStart+2, 0x00,0x00,0xff);
//
//			target.put(row, colEnd-2, 0x00,0x00,0xff);
//			target.put(row, colEnd-1, 0x00,0x00,0xff);
			target.put(row, colEnd, 0,0,255);
    	}
		//paint col
    	for(int col=colStart;col<=colEnd;col++){
    		target.put(rowStart, col, 0,0,255);
    		target.put(rowEnd, col, 0,0,255);
    	}
    	//paint text
//    	Core.putText(target, ""+index, new Point(colStart, rowStart+25)
//    	, Core.FONT_HERSHEY_SIMPLEX|Core.FONT_ITALIC, 1, new Scalar(0x00,0x00,0xff),2,8,false);
	}
	public boolean diffNodeImg(AGNode node1, AGNode node2){
		try{
	    	Mat subMat1 = getSubMat(source1, node1.y1, node1.y2, node1.x1, node1.x2);
//	    	Mat subMat2 = getSubMat(source2, node2.y1+91, node2.y2+91, node2.x1+196, node2.x2+196);
	    	Mat subMat2 = getSubMat(source2, node2.y1, node2.y2, node2.x1, node2.x2);
	    	if(subMat1 == null||subMat1.empty() || subMat2 == null || subMat2.empty()) return false;
	    	double result = compareImage(subMat1, subMat2,node1.getDomNode().getxPath().equals("/HTML/BODY/DIV[3]/DIV[2]/DIV/DIV/DIV/DIV[3]/UL/LI"));
	    	subMat1.release();
	    	subMat2.release();
	    	return result<THREADSHOLD_CORREL;//>THREADSHOLD_BHATTACHARYYA;//>THREADSHOLD_CHISQR;//
		}catch(Exception e){
			e.printStackTrace();
		}
		return true;
	}
	private Mat getSubMat(Mat source, int rowStart, int rowEnd, int colStart, int colEnd ){
		if(rowEnd > source.rows() || colEnd > source.cols()){
			return null;
		}
		rowStart = rowStart>0?rowStart:0;
		colStart = colStart>0?colStart:0;
//		rowEnd = rowEnd<source.rows()?rowEnd:source.rows();
//		colEnd = colEnd<source.cols()?colEnd:source.cols();
		return source.submat(rowStart, rowEnd, colStart, colEnd).clone();
	}
	
	private double compareImage(Mat mat1, Mat mat2, boolean debug) throws Exception{
		if((mat1.cols()==0||mat1.rows()==0) && (mat2.cols()==0||mat2.rows()==0)) return 0;
		if(debug){
    		Highgui.imwrite("D:/ReplayResource/chrome1.png", mat1);
			Highgui.imwrite("D:/ReplayResource/firefox1.png", mat2);
    	}
		try{
	    	Imgproc.cvtColor(mat1, mat1, Imgproc.COLOR_BGR2HSV);
	    	Imgproc.cvtColor(mat2, mat2, Imgproc.COLOR_BGR2HSV);
		}catch(Exception exception){
			exception.printStackTrace();
			throw(exception);
		}
    	if(debug){
    		Highgui.imwrite("D:/ReplayResource/chrome2.png", mat1);
			Highgui.imwrite("D:/ReplayResource/firefox2.png", mat2);
    	}
    	MatOfFloat ranges = new MatOfFloat(0f, 180f, 0f, 256f);
    	MatOfInt histSize = new MatOfInt(50,60);
    	Imgproc.calcHist(Arrays.asList(mat1), new MatOfInt(0,1), new Mat(), mat1, histSize, ranges);
    	Core.normalize(mat1, mat1, 0, 1, Core.NORM_MINMAX, -1, new Mat());
    	Imgproc.calcHist(Arrays.asList(mat2), new MatOfInt(0,1), new Mat(), mat2, histSize, ranges);
    	Core.normalize(mat2, mat2, 0, 1, Core.NORM_MINMAX, -1, new Mat());
    	if(debug){
    		Highgui.imwrite("D:/ReplayResource/chrome3.png", mat1);
			Highgui.imwrite("D:/ReplayResource/firefox3.png", mat2);
    	}
    	return Imgproc.compareHist(mat1, mat2, Imgproc.CV_COMP_CORREL);//Imgproc.CV_COMP_BHATTACHARYYA);//Imgproc.CV_COMP_CHISQR);//
    }
}
